package com.xyy.saas.payment.config;

import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.adpater.chinabank.constants.ChinaBankHystrixConstants;
import com.xyy.saas.payment.adpater.impl.YopAdapter;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.PayBo;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.payment.core.dto.PayDto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author wangtianqi
 * @date 2020/8/4 16:22
 */
public class DegradedPay4YopHystrixCommand extends HystrixCommand<ResultVO> {

    private static Logger LOGGER = LoggerFactory.getLogger(DegradedPay4YopHystrixCommand.class);

    private PayDto payDto;

    private YopAdapter yopAdapter;

    private RouteManager routeManager;


//    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
//                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2"),
//                    //超时
//                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000"),
//                    //出错百分比阈值，当达到此阈值后，开始短路。默认50%）
//                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
//                    //此属性设置统计滚动窗口的持续时间（以毫秒为单位）。对于断路器的使用和发布Hystrix保持多长时间的指标。 此属性不允许热修改
//                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
//                    //并发请求数量 单机瞬间并发 50
//                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "50"),

    public DegradedPay4YopHystrixCommand(PayDto payDto, YopAdapter yopAdapter, RouteManager routeManager) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(ChinaBankHystrixConstants.COMMAND_KEY))
        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                .withCircuitBreakerSleepWindowInMilliseconds(ChinaBankHystrixConstants.getIntConfigValue(ChinaBankHystrixConstants.SLEEP_WINDOW_KEY))
                .withCircuitBreakerRequestVolumeThreshold(ChinaBankHystrixConstants.getIntConfigValue(ChinaBankHystrixConstants.REQUEST_VOLUME))
                .withCircuitBreakerErrorThresholdPercentage(ChinaBankHystrixConstants.getIntConfigValue(ChinaBankHystrixConstants.ERROR_THRESHOLD_PERCENTAGE))
                .withExecutionTimeoutInMilliseconds(ChinaBankHystrixConstants.getIntConfigValue(ChinaBankHystrixConstants.EXECUTION_TIME_OUT))
                .withFallbackIsolationSemaphoreMaxConcurrentRequests(ChinaBankHystrixConstants.getIntConfigValue(ChinaBankHystrixConstants.SEMAPHORE_MAX_CONCURRENT))
                .withCircuitBreakerEnabled(true)
        ));
        this.payDto = payDto;
        this.yopAdapter = yopAdapter;
        this.routeManager = routeManager;
    }

    @Override
    protected ResultVO run() throws Exception {
        try {
            PayBo payBo =   yopAdapter.pay(payDto);

            if(StringUtils.isEmpty(payBo.getPayNO())) {
                return ResultVO.createError(ResultCodeEnum.ORDER_TIME_EXPIRE);
            }

            return ResultVO.createSuccess(payBo);
        }
        catch(Exception ex) {
            LOGGER.error("DegradedPay4YopHystrixCommand Yop channel pay error=" + ex.getMessage() ,ex);
            throw ex;
        }
    }

    @Override
    protected ResultVO getFallback() {
        LOGGER.error("DegradedPay4YopHystrixCommand Yop -> Direct, payDto：{}", JSONObject.toJSONString(payDto));

        try {
            return routeManager.fallBackDegradedPay(payDto);
        }
        catch(PaymentException e) {
            LOGGER.error("DegradedPay4YopHystrixCommand#getFallback ", e);
            return ResultVO.createError(e.getErrCode(), e.getErrMsg(), "");
        }
    }
}